/**
 * 
 */
package org.ranch.web.controllers;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.ranch.api.ConceptCategoryAnnotation;
import org.ranch.api.DefaultConceptCategories;
import org.ranch.api.security.PermissionConstants;
import org.ranch.api.service.AnimalSearchParameters;
import org.ranch.api.service.ConceptService;
import org.ranch.api.service.FarmService;
import org.ranch.api.service.PersonService;
import org.ranch.api.utils.RanchUtil;
import org.ranch.model.Animal;
import org.ranch.model.Concept;
import org.ranch.model.ConceptCategory;
import org.ranch.model.Farm;
import org.ranch.model.Kraal;
import org.ranch.model.Person;
import org.ranch.model.exception.RanchValidationException;
import org.ranch.web.WebConstants;
import org.ranch.web.WebUtils;
import org.ranch.web.forms.GenericCommand;
import org.ranch.web.forms.GenericCommandValue;
import org.ranch.web.propertyeditors.DatePropertyEditor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

/**
 * controller to handle operations to on farms
 * 
 * @author Jmpango
 * 
 */
@Controller
@RequestMapping("farm")
public class FarmController {

    @Autowired
    private FarmService farmService;

    @Autowired
    private PersonService personService;

    @Autowired
    private ConceptService conceptService;

    @Autowired
    private DatePropertyEditor datePropertyEditor;

    public static final String ANIMAL_SEARCH_MODEL_PARAM_TYPE = "type";
    public static final String ANIMAL_SEARCH_MODEL_PARAM_HEALTH_STATUS = "healthstatus";
    public static final String ANIMAL_SEARCH_MODEL_PARAM_COLOR = "color";
    public static final String ANIMAL_SEARCH_MODEL_PARAM_KRAAL = "kraal";
    public static final String ANIMAL_SEARCH_MODEL_PARAM_BREED = "breed";
    public static final String ANIMAL_SEARCH_MODEL_PARAM_DATEOFBIRTH = "dateOfBirth";
    public static final String ANIMAL_SEARCH_MODEL_PARAM_STATUS = "status";
    public static final String ANIMAL_SEARCH_MODEL_PARAM_Weight = "weight";
    public static final String ANIMAL_SEARCH_FORM_COMMAND_NAME = "animalsearch";

    /**
     * web data binder
     * 
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {

    }

    /**
     * handles the request for the farm view
     * 
     * @param model
     *            map for page attributes
     * @return
     */
    @Secured(PermissionConstants.PERM_VIEW_FARM)
    @RequestMapping(method = RequestMethod.GET, params = { "action=view" })
    public ModelAndView viewFarmHandler(
	    @RequestParam(value = "pageNo", required = false) Integer pageNo,
	    ModelMap model) {
	List<Farm> farms = farmService.getFarms(pageNo);
	if (farms != null) {
	    model.put("farmList", farms);
	}

	WebUtils.prepareNavigation("Farm", farmService.getTotalNumberOfFarm(), farms.size(),
		((pageNo == null) ? 1 : pageNo), "farm?action=view", model);

	return new ModelAndView("farm", model);
    }
    
    @Secured(PermissionConstants.PERM_EDIT_FARM)
    @RequestMapping(method = RequestMethod.GET, params = { "action=add" })
    public ModelAndView addFarmHandler(ModelMap model) {
	prepareFarm(model);
	model.put("farm", new Farm());
	return new ModelAndView("addFarm", model);
    }

    /**
     * @param model
     * 
     */
    private void prepareFarm(ModelMap model) {
	List<Person> persons = personService.getPersons();
	if (persons != null) {
	    model.put("manager", persons);
	}
    }
    
    @Secured(PermissionConstants.PERM_EDIT_FARM)
    @RequestMapping(method = RequestMethod.POST, params = { "action=save" })
    public ModelAndView saveFarmHandler(@ModelAttribute("farm") Farm farmModel, ModelMap model,
	    HttpServletRequest request) {

	Farm farm = farmModel;
	if (StringUtils.isNotBlank(farmModel.getId())) {
	    farm = farmService.getFarmById(farmModel.getId());
	    copyFarm(farmModel, farm);
	}else{
	    farm.setId(null);
	}

	try {
	    farmService.validateFarm(farm);
	    farmService.save(farm);
	} catch (RanchValidationException ex) {
	    model.put(WebConstants.MODEL_ATTRIBUTE_ERROR_MESSAGE, ex.getMessage());
	    prepareFarm(model);
	    model.put("farm", farmModel);
	    return new ModelAndView("addFarm", model);
	}
	model.put(WebConstants.MODEL_ATTRIBUTE_SYSTEM_MESSAGE,
		"Farm saved sucessfully!!!");
	return viewFarmHandler(null, model);
    }

    /**
     * @param farmModel
     * @param farm
     */
    private void copyFarm(Farm fromFarmModel, Farm toFarm) {
	toFarm.setId(fromFarmModel.getId());
	toFarm.setAddress(fromFarmModel.getAddress());
	toFarm.setManager(fromFarmModel.getManager());
	toFarm.setName(fromFarmModel.getName());
    }

    @Secured(PermissionConstants.PERM_EDIT_FARM)
    @RequestMapping(method = RequestMethod.GET, params = { "action=edit" })
    public ModelAndView editFarmHandler(
	    @RequestParam("id") String id,
	    ModelMap model) {

	Farm farm = farmService.getFarmById(id);
	if (farm != null) {
	    prepareFarm(model);
	    model.put("farm", farm);
	    return new ModelAndView("addFarm", model);
	}

	return null;
    }
    @Secured(PermissionConstants.PERM_DELETE_FARM)
    @RequestMapping(method = RequestMethod.GET, params = { "action=delete",
	    "item=farm" })
    public ModelAndView deleteFarm(
	    @RequestParam("farmIdsToDelete") String farmIdsToDelete,
	    @RequestParam("pageNo") int pageNo, ModelMap model) {
	try {
	    List<String> farmIds = convertStringToList(farmIdsToDelete, ",");
	    for (String id : farmIds) {
		Farm farm = farmService.getFarmById(id);
		if (farm != null) {
		    farmService.delete(farm);
		}
	    }

	    model.put(WebConstants.MODEL_ATTRIBUTE_SYSTEM_MESSAGE,
		    "Farm(s) deleted succesfully");
	} catch (Exception ex) {
	    model.put(WebConstants.MODEL_ATTRIBUTE_ERROR_MESSAGE, "Error: "
		    + ex.getMessage());
	}

	return viewFarmHandler(pageNo, model);
    }

    private static List<String> convertStringToList(String longString,
	    String separator) {
	String[] stringArray;
	if (separator == null)
	    separator = ",";
	if (separator == "")
	    separator = ",";
	stringArray = longString.split(separator);

	List<String> list = new ArrayList<String>();
	for (int i = 0; i < stringArray.length; i++)
	    list.add(i, stringArray[i]);

	return list;
    }

    @Secured(PermissionConstants.PERM_VIEW_KRAAL)
    @RequestMapping(method = RequestMethod.GET, params = { "action=view",
	    "item=farm" })
    public ModelAndView viewKraal(@RequestParam("id") String farmId,
	    ModelMap model) {
	Farm farm = farmService.getFarmById(farmId);

	if (farm != null) {
	    model.put("farm", farm);
	    model.put("kraals", farm.getKraals());
	    return new ModelAndView("kraalView", model);
	}
	return null;
    }

    @Secured(PermissionConstants.PERM_EDIT_KRAAL)
    @RequestMapping(method = RequestMethod.GET, params = { "action=add", "item=kraal" })
    public ModelAndView addKraal(@RequestParam("farmid") String farmId, ModelMap model) {
	Farm farm = farmService.getFarmById(farmId);

	if (farm != null) {
	    model.put("farm", farm);
	    model.put("kraal", new Kraal());
	}
	return new ModelAndView("addKraal", model);
    }

    @Secured(PermissionConstants.PERM_EDIT_KRAAL)
    @RequestMapping(method = RequestMethod.POST, params = { "action=save", "item=kraal" })
    public ModelAndView saveKraal(@RequestParam("farmid") String farmId,
	    @ModelAttribute("kraal") Kraal kraalModel, ModelMap model) {
	Farm farm = farmService.getFarmById(farmId);

	if (farm != null) {
	    Kraal kraalOldModel = kraalModel;

	    if (StringUtils.isNotBlank(kraalModel.getId())) {
		kraalOldModel = getKraal(farmService.getFarmById(farmId).getKraals(),
			kraalModel.getId());
		copyKraals(kraalOldModel, kraalModel);
	    } else {
		kraalOldModel.setId(null);
		farmService.getFarmById(farmId).addKraal(kraalOldModel);
	    }

	    try {
		farmService.validateKraal(kraalOldModel);
		farmService.save(farm);

	    } catch (RanchValidationException e) {
		model.put(WebConstants.MODEL_ATTRIBUTE_ERROR_MESSAGE, e.getMessage());
		model.put("farm", farm);
		model.put("kraal", kraalModel);
		return new ModelAndView("addKraal", model);
	    }

	}
	model.put(WebConstants.MODEL_ATTRIBUTE_SYSTEM_MESSAGE, "Kraal saved sucessfully.");
	model.put("farm", farmService.getFarmById(farmId));
	model.put("kraals", farmService.getFarmById(farmId).getKraals());
	return new ModelAndView("kraalView", model);
    }

    /**
     * @param kraals
     * @param id
     * @return
     */
    private Kraal getKraal(List<Kraal> kraals, String kraalId) {
	for (Kraal kraal : kraals) {
	    if (kraal.getId().equals(kraalId)) {
		return kraal;
	    }
	}
	return null;
    }

    /**
     * @param kraalOldModel
     * @param kraalModel
     */
    private void copyKraals(Kraal toKraal, Kraal fromKraal) {
	toKraal.setName(fromKraal.getName());
	toKraal.setId(fromKraal.getId());
    }

    @Secured(PermissionConstants.PERM_EDIT_KRAAL)
    @RequestMapping(method = RequestMethod.GET, params = { "action=edit",
	    "item=kraal" })
    public ModelAndView editKraalHandler(@RequestParam("kraalid") String kraalId,
	    @RequestParam("farmid") String farmId,
	    ModelMap model) {
	Farm farm = farmService.getFarmById(farmId);
	if (farm != null) {
	    Kraal kraal = getKraal(farm.getKraals(), kraalId);
	    model.put("farm", farm);
	    model.put("kraal", kraal);
	    return new ModelAndView("addKraal", model);
	}
	return null;
    }

    /**
     * handler method to handle a request for deleting kraal(s)
     * 
     * @param kraalIds
     * @param model
     * @return
     */
    @Secured(PermissionConstants.PERM_DELETE_KRAAL)
    @RequestMapping(method = RequestMethod.POST, params = { "action=delete",
			"item=kraal" })
    public void deleteKraalHandler(@RequestParam("farmid") String farmId,
			@RequestParam("selectedKraal") List<String> kraalIds,
			HttpServletResponse response) {

	try {

	    Farm farm = farmService.getFarmById(farmId);

	    if (farm != null) {

		if (kraalIds != null && kraalIds.size() > 0) {
		    for (String kraalId : kraalIds) {
			Kraal kraal = getKraal(farm.getKraals(), kraalId);

			if (kraal != null) {
			    kraal.setFarm(farm);
			    farm.removeKraal(kraal);
			    farmService.delete(kraal);
			}
		    }
		    response.setStatus(HttpServletResponse.SC_OK);
		    response.getWriter().write("Kraal(s) deleted successfully");
		} else {
		    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
		    response.getWriter().write("no Kraal(s) supplied for deleting");
		}
	    }

	} catch (Exception e) {
	    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
	}
    }

    @Secured(PermissionConstants.PERM_VIEW_ANIMAL)
    @RequestMapping(method = RequestMethod.GET, params = { "action=view", "item=kraalanimals" })
    public ModelAndView viewKraalAnimals(@RequestParam("kraalid") String kraalId, ModelMap model) {

	Kraal kraal = new Kraal();
	if (kraalId != null) {
	    kraal = farmService.getKraalById(kraalId);

	    if (kraal != null) {
		model.put("kraal", kraal);
		model.put("animals", kraal.getAnimals());
	    }
	    return new ModelAndView("animalView", model);
	} else {

	    model.put(WebConstants.MODEL_ATTRIBUTE_ERROR_MESSAGE,
		    "the kraal id submitted doesnot exist.");
	    return viewKraal(kraal.getFarm().getId(), model);
	}
    }

    @RequestMapping(method = RequestMethod.GET, params = { "item=pic" })
    public void animalPictureHandler(@RequestParam("animalid") String animalId,
		    HttpServletResponse response) throws Exception {

	Animal animal = farmService.getAnimalById(animalId);

	if (animal != null) {
	    if (animal.getPicture() != null && animal.getPicture().length > 0) {

		String contentType = "image/jpeg";
		writePictureOnResponse(contentType, animal.getPicture(), response);
	    }
	}
    }

    /**
     * writes the given bytes for a picture on the given servlet response.
     * 
     * @param contentType
     *            the content type of the image e.g. image/jpeg
     * @param pic
     * @param response
     * @throws IOException
     */
    private void writePictureOnResponse(String contentType, byte[] pic, HttpServletResponse response)
	    throws IOException {
	try {
	    response.setContentType(contentType);
	    response.getOutputStream().write(pic);
	} catch (IOException e) {
	} finally {
	    response.getOutputStream().flush();
	}
    }

    @Secured(PermissionConstants.PERM_VIEW_ANIMAL)
    @RequestMapping(method = RequestMethod.GET, params = { "action=add", "item=animal" })
    public ModelAndView addAnimal(@RequestParam("kraalid") String kraalId, ModelMap model) {
	Kraal kraal = farmService.getKraalById(kraalId);
	if (kraal != null) {
	    model.put("kraal", kraal);
	    model.put("animal", new Animal());
	    prepareAnimal(model);
	    return new ModelAndView("addAnimal", model);
	}

	return null;
    }

    @Secured(PermissionConstants.PERM_EDIT_ANIMAL)
    @RequestMapping(method = RequestMethod.GET, params = { "action=edit", "item=animal" })
    public ModelAndView editAnimal(@RequestParam("animalid") String animalId, ModelMap model) {
	Animal animal = farmService.getAnimalById(animalId);
	if (animal != null) {
	    model.put("kraal", animal.getKraal());
	    model.put("animal", animal);
	    model.put("qpage", "1");
	    prepareAnimal(model);
	    return new ModelAndView("addAnimal", model);
	}

	return null;
    }

    /**
     * @param model
     */
    private void prepareAnimal(ModelMap model) {
	try {
	    ConceptCategoryAnnotation colourCateoryAnnotation = RanchUtil
		    .getConceptCategoryFieldAnnotation(DefaultConceptCategories.class,
			    DefaultConceptCategories.COLOR_TYPE);

	    if (colourCateoryAnnotation != null) {
		ConceptCategory concept = conceptService
			.getConceptCategoryById(colourCateoryAnnotation.id());
		if (concept != null) {
		    model.put("color", conceptService.getConceptsByCategory(concept));
		}
	    }
	} catch (Exception e) {
	}

	try {
	    ConceptCategoryAnnotation healthStatusCateoryAnnotation = RanchUtil
		    .getConceptCategoryFieldAnnotation(DefaultConceptCategories.class,
			    DefaultConceptCategories.HEALTH_STATUS_TYPE);

	    if (healthStatusCateoryAnnotation != null) {
		ConceptCategory concept = conceptService
			.getConceptCategoryById(healthStatusCateoryAnnotation.id());
		if (concept != null) {
		    model.put("healthStatus", conceptService.getConceptsByCategory(concept));
		}
	    }
	} catch (Exception e) {
	}

	try {
	    ConceptCategoryAnnotation breedCateoryAnnotation = RanchUtil
		    .getConceptCategoryFieldAnnotation(DefaultConceptCategories.class,
			    DefaultConceptCategories.BREED_TYPE);

	    if (breedCateoryAnnotation != null) {
		ConceptCategory concept = conceptService
			.getConceptCategoryById(breedCateoryAnnotation.id());
		if (concept != null) {
		    model.put("breed", conceptService.getConceptsByCategory(concept));
		}
	    }
	} catch (Exception e) {
	}

	try {
	    ConceptCategoryAnnotation animalTypeCateoryAnnotation = RanchUtil
		    .getConceptCategoryFieldAnnotation(DefaultConceptCategories.class,
			    DefaultConceptCategories.ANIMAL_TYPE);

	    if (animalTypeCateoryAnnotation != null) {
		ConceptCategory concept = conceptService
			.getConceptCategoryById(animalTypeCateoryAnnotation.id());
		if (concept != null) {
		    model.put("type", conceptService.getConceptsByCategory(concept));
		}
	    }
	} catch (Exception e) {
	}

	try {
	    ConceptCategoryAnnotation animalStatusCateoryAnnotation = RanchUtil
		    .getConceptCategoryFieldAnnotation(DefaultConceptCategories.class,
			    DefaultConceptCategories.STATUS_TYPE);

	    if (animalStatusCateoryAnnotation != null) {
		ConceptCategory concept = conceptService
			.getConceptCategoryById(animalStatusCateoryAnnotation.id());
		if (concept != null) {
		    model.put("status", conceptService.getConceptsByCategory(concept));
		}
	    }
	} catch (Exception e) {
	}
    }
    
    @Secured(PermissionConstants.PERM_EDIT_ANIMAL)
    @RequestMapping(method = RequestMethod.POST, params = { "action=save", "item=animal" })
    public ModelAndView saveAnimalHandler(@ModelAttribute("animal") Animal newAnimal,
	    @RequestParam("kraalid") String kraalid,
	    ModelMap model, @RequestParam("animalid") String animalId, @RequestParam(
		    value = "file", required = true) MultipartFile photoFile, @RequestParam(
		    value = "qpage", required = false) String qpage) {
	Animal oldAnimal = null;
	Kraal kraal = null;
	String qpag = "";
	try {
	    if (kraalid != null) {
		kraal = farmService.getKraalById(kraalid);
		newAnimal.setKraal(kraal);
		if (StringUtils.isNotEmpty(animalId)) {
		    newAnimal.setId(animalId);
		}

		if (StringUtils.isNotEmpty(qpage)) {
		    qpag = qpage;
		}
		oldAnimal = newAnimal;
		farmService.validateAnimal(newAnimal);

		try {
		    validateAnimalImage(photoFile);
		} catch (RanchValidationException e1) {
		    model.put("kraal", kraal);
		    model.put("animal", oldAnimal);
		    model.put("qpage", qpag);
		    prepareAnimal(model);
		    model.put(WebConstants.MODEL_ATTRIBUTE_ERROR_MESSAGE, e1.getMessage());
		    return new ModelAndView("addAnimal", model);
		}

		if (StringUtils.isNotBlank(newAnimal.getId())) {
		    oldAnimal = getAnimal(kraal.getAnimals(),
			    newAnimal.getId());
		    copyAnimal(oldAnimal, newAnimal);
		} else {
		    oldAnimal.setId(null);
		    if (photoFile != null && photoFile.getSize() > 0) {
			try {
			    oldAnimal.setPicture(photoFile.getBytes());
			} catch (IOException e) {
			    e.printStackTrace();
			}
		    }

		    kraal.addAnimal(oldAnimal);
		}

		farmService.save(kraal);

		if (StringUtils.isNotEmpty(qpage)) {
		    model.put(WebConstants.MODEL_ATTRIBUTE_SYSTEM_MESSAGE,
			    "Animal Editted sucessfully.");
		    return viewAnimalPageHandler(oldAnimal.getId(), model);
		} else {
		    model.put(WebConstants.MODEL_ATTRIBUTE_SYSTEM_MESSAGE,
			    "Animal saved sucessfully.");
		    return viewKraalAnimals(kraalid, model);
		}
	    }
	} catch (RanchValidationException e) {
	    model.put("kraal", kraal);
	    model.put("animal", oldAnimal);
	    model.put("qpage", qpag);
	    prepareAnimal(model);
	    model.put(WebConstants.MODEL_ATTRIBUTE_ERROR_MESSAGE, e.getMessage());
	    return new ModelAndView("addAnimal", model);
	}
	return null;
    }

    @RequestMapping(method = RequestMethod.GET, params = { "action=view", "item=pic" })
    public void animalPictureHandler(@RequestParam("kraalid") String kraalId,
	    @RequestParam("animalid") String animalid,
	    HttpServletResponse response) throws Exception {

	Kraal kraal = farmService.getKraalById(kraalId);
	if (kraal != null) {
	    Animal animal = getAnimal(kraal.getAnimals(), animalid);
	    if (animal.getPicture() != null && animal.getPicture().length > 0) {
		String contentType = "image/jpeg";
		writePictureOnResponse(contentType, animal.getPicture(), response);
	    }
	}
    }

    /**
     * @param photoFile
     */
    private void validateAnimalImage(MultipartFile photoFile) throws RanchValidationException {
	if (!WebUtils.isFileAnImage(photoFile))
	    throw new RanchValidationException(
		    "the file uploaded for the user photo is not an image.");

	if (!WebUtils.isValidSize(photoFile, WebConstants.DEFAULT_IMAGE_SIZE_IN_BYTES)) {
	    throw new RanchValidationException(String.format(
		    "the user photo exceeds the required size of >> %s bytes",
		    WebConstants.DEFAULT_IMAGE_SIZE_IN_BYTES));

	}

    }

    /**
     * @param oldAnimal
     * @param newAnimal
     */
    private void copyAnimal(Animal oldAnimal, Animal newAnimal) {
	oldAnimal.setId(newAnimal.getId());
	oldAnimal.setType(newAnimal.getType());
	oldAnimal.setEarTag(newAnimal.getEarTag());
	oldAnimal.setWeight(newAnimal.getWeight());
	oldAnimal.setName(newAnimal.getName());
	oldAnimal.setHealthStatus(newAnimal.getHealthStatus());
	oldAnimal.setDateOfBirth(newAnimal.getDateOfBirth());
	oldAnimal.setColour(newAnimal.getColour());
	oldAnimal.setKraal(newAnimal.getKraal());
	oldAnimal.setPurchaseDate(newAnimal.getPurchaseDate());
	oldAnimal.setDescription(newAnimal.getDescription());
	oldAnimal.setBreed(newAnimal.getBreed());
	oldAnimal.setBirthWeight(newAnimal.getBirthWeight());
	oldAnimal.setBuyingPrice(newAnimal.getBuyingPrice());
	oldAnimal.setChildren(newAnimal.getChildren());
	oldAnimal.setBirthWeight(newAnimal.getBirthWeight());

    }

    /**
     * @param animals
     * @param newAnimal
     * @return
     */
    private Animal getAnimal(List<Animal> animals, String animalid) {
	for (Animal animal : animals) {
	    if (animal.getId().equals(animalid)) {
		return animal;
	    }
	}
	return null;
    }

    /**
     * handler method to handle a request for deleting kraal(s)
     * 
     * @param kraalIds
     * @param model
     * @return
     * @throws IOException
     */
    @Secured(PermissionConstants.PERM_DELETE_ANIMAL)
    @RequestMapping(method = RequestMethod.POST, params = { "action=delete",
			"item=animal" })
    public void deleteAnimalHandler(@RequestParam("kraalid") String kraalId,
			@RequestParam("selectedAnimal") List<String> animalIds,
			HttpServletResponse response) throws IOException {

	try {
	    Kraal kraal = farmService.getKraalById(kraalId);

	    if (kraal != null) {

		if (animalIds != null && animalIds.size() > 0) {
		    for (String animalId : animalIds) {
			Animal animal = getAnimal(kraal.getAnimals(), animalId);

			if (animal != null) {
			    animal.setKraal(kraal);
			    kraal.removeAnimal(animal);
			    farmService.delete(animal);
			}
		    }
		    response.setStatus(HttpServletResponse.SC_OK);
		    response.getWriter().write("Animal(s) deleted successfully");
		} else {
		    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
		    response.getWriter().write("no Animal(s) supplied for deleting");
		}
	    }

	} catch (Exception e) {
	    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
	    response.getWriter().write(e.getMessage());
	}
    }

    /**
     * handler method to handle the request for searching animals
     */
    @Secured(PermissionConstants.PERM_VIEW_ANIMAL)
    @RequestMapping(method = RequestMethod.POST, params = { "action=search",
			"item=animal" })
    public ModelAndView searchAnimalByEarTag(
	    @RequestParam("kraalid") String kraalid,
			@RequestParam(WebConstants.SEARCH_QUERY_REQUEST_PARAMETER_NAME) String query,
			ModelMap model) {
	List<Animal> animals = null;
	Kraal kraal = farmService.getKraalById(kraalid);
	if (kraal != null) {
	    if (StringUtils.isEmpty(query)) {
		animals = kraal.getAnimals();
	    } else {
		animals = farmService.searchAnimalByTagNo(query, kraalid);
		model.put(WebConstants.MODEL_ATTRIBUTE_SYSTEM_MESSAGE,
			"search for query >> \"" + query
					+ "\" completed with " + animals.size() + " result(s)");
	    }

	    model.put("animals", animals);
	    model.put("kraal", kraal);
	    return new ModelAndView("animalView", model);
	}
	return null;
    }

    @RequestMapping(method = RequestMethod.GET, params = { "action=view", "item=animal" })
    public ModelAndView viewAnimalPageHandler(@RequestParam("animalid") String animalid,
	    ModelMap model) {
	if (StringUtils.isNotEmpty(animalid)) {
	    model.put("animal", farmService.getAnimalById(animalid));
	    return new ModelAndView("singleAnimalView", model);
	}
	return null;
    }

    /**
     * handles the request for the report view
     * 
     * @param model
     *            map for page attributes
     * @return
     */
    @Secured(PermissionConstants.PERM_VIEW_REPORT)
    @RequestMapping(method = RequestMethod.GET, params = { "action=view", "item=report" })
    public ModelAndView viewReportHandler(
	    @RequestParam(value = "pageNo", required = false) Integer pageNo,
	    ModelMap model) {
	/*
	 * List<Animal> animalList = farmService.getAnimals(pageNo); if
	 * (animalList != null) { model.put("animals", animalList); }
	 * 
	 * WebUtils.prepareNavigation("Animal", farmService
	 * .getTotalNumberOfAnimal(), animalList.size(), ((pageNo == null) ? 1 :
	 * pageNo), "farm?action=view&item=report", model);
	 */

	prepareAnimalSearchFormLookUpLists(model);
	prepareAnimalSearchCommand(model, new AnimalSearchParameters());

	return new ModelAndView("reportView", model);
    }

    /**
     * @param model
     * @param animalSearchParameters
     */
    private void prepareAnimalSearchCommand(ModelMap model, AnimalSearchParameters params) {
	GenericCommand searchCommand = new GenericCommand();
	if (params.getType() != null) {
	    searchCommand.getPropertiesMap().put(FarmController.ANIMAL_SEARCH_MODEL_PARAM_TYPE,
			new GenericCommandValue(params.getType().getId()));
	}

	if (params.getHealthStatus() != null) {
	    searchCommand.getPropertiesMap().put(
		    FarmController.ANIMAL_SEARCH_MODEL_PARAM_HEALTH_STATUS,
			new GenericCommandValue(params.getHealthStatus().getId()));
	}

	if (params.getColor() != null) {
	    searchCommand.getPropertiesMap().put(FarmController.ANIMAL_SEARCH_MODEL_PARAM_COLOR,
			new GenericCommandValue(params.getColor().getId()));
	}

	if (params.getKraal() != null) {
	    searchCommand.getPropertiesMap().put(FarmController.ANIMAL_SEARCH_MODEL_PARAM_KRAAL,
			new GenericCommandValue(params.getKraal().getId()));
	}

	if (params.getBreed() != null) {
	    searchCommand.getPropertiesMap().put(FarmController.ANIMAL_SEARCH_MODEL_PARAM_BREED,
			new GenericCommandValue(params.getBreed().getId()));
	}

	if (params.getBirthYear() != null) {
	    datePropertyEditor.setValue(params.getDateOfBirth());
	    searchCommand.getPropertiesMap().put(
		    FarmController.ANIMAL_SEARCH_MODEL_PARAM_DATEOFBIRTH,
		    new GenericCommandValue(datePropertyEditor.getAsText()));
	} else {
	    searchCommand.getPropertiesMap().put(
		    "FarmController.ANIMAL_SEARCH_MODEL_PARAM_DATEOFBIRTH",
		    new GenericCommandValue(null));
	}

	if (params.getStatus() != null) {
	    searchCommand.getPropertiesMap().put(FarmController.ANIMAL_SEARCH_MODEL_PARAM_STATUS,
			new GenericCommandValue(params.getStatus().getId()));
	}

	if (params.getWeight() > 0) {
	    searchCommand.getPropertiesMap().put(FarmController.ANIMAL_SEARCH_MODEL_PARAM_Weight,
			new GenericCommandValue(String.valueOf(params.getWeight())));
	}

	model.put(FarmController.ANIMAL_SEARCH_FORM_COMMAND_NAME, searchCommand);
    }

    /**
     * @param model
     */
    private void prepareAnimalSearchFormLookUpLists(ModelMap model) {
	try {
	    ConceptCategoryAnnotation typeCategory = RanchUtil
		    .getConceptCategoryFieldAnnotation(
			    DefaultConceptCategories.class,
			    DefaultConceptCategories.ANIMAL_TYPE);

	    List<Concept> types = conceptService
		    .getConceptsByCategory(conceptService
			    .getConceptCategoryById(typeCategory.id()));
	    model.put("type", types);
	} catch (SecurityException e) {
	} catch (NoSuchFieldException e) {
	}

	try {
	    ConceptCategoryAnnotation healthStatusCategory = RanchUtil
		    .getConceptCategoryFieldAnnotation(
			    DefaultConceptCategories.class,
			    DefaultConceptCategories.HEALTH_STATUS_TYPE);

	    List<Concept> healthStatus = conceptService
		    .getConceptsByCategory(conceptService
			    .getConceptCategoryById(healthStatusCategory.id()));
	    model.put("healthStatus", healthStatus);
	} catch (SecurityException e) {
	} catch (NoSuchFieldException e) {
	}

	try {
	    ConceptCategoryAnnotation colorCategory = RanchUtil
		    .getConceptCategoryFieldAnnotation(
			    DefaultConceptCategories.class,
			    DefaultConceptCategories.COLOR_TYPE);

	    List<Concept> colors = conceptService
		    .getConceptsByCategory(conceptService
			    .getConceptCategoryById(colorCategory.id()));
	    model.put("colors", colors);
	} catch (SecurityException e) {
	} catch (NoSuchFieldException e) {
	}

	try {
	    ConceptCategoryAnnotation breedCategory = RanchUtil
		    .getConceptCategoryFieldAnnotation(
			    DefaultConceptCategories.class,
			    DefaultConceptCategories.BREED_TYPE);

	    List<Concept> breeds = conceptService
		    .getConceptsByCategory(conceptService
			    .getConceptCategoryById(breedCategory.id()));
	    model.put("breeds", breeds);
	} catch (SecurityException e) {
	} catch (NoSuchFieldException e) {
	}

	try {
	    ConceptCategoryAnnotation statusCategory = RanchUtil
		    .getConceptCategoryFieldAnnotation(
			    DefaultConceptCategories.class,
			    DefaultConceptCategories.STATUS_TYPE);

	    List<Concept> status = conceptService
		    .getConceptsByCategory(conceptService
			    .getConceptCategoryById(statusCategory.id()));
	    model.put("status", status);
	} catch (SecurityException e) {
	} catch (NoSuchFieldException e) {
	}

	model.put("kraals", farmService.getKraals());
	model.put("farms", farmService.getFarms());

	List<Person> persons = new ArrayList<Person>();
	for (Person p : personService.getPersons()) {
	    if (p.getResponsibility().getName().equals("Manager")) {
		persons.add(p);
	    }
	}
	model.put("managers", persons);
    }

    @Secured(PermissionConstants.PERM_VIEW_REPORT)
    @RequestMapping(method = RequestMethod.POST, params = { "action=search" })
    public ModelAndView animalSearchHandler(
	    @ModelAttribute("animalsearch") GenericCommand searchCommand,
	    @RequestParam(value = "pageNo", required = false) Integer pageNo,
	    ModelMap model) {

	if (pageNo == null || pageNo <= 0) {
	    pageNo = 1;
	}

	AnimalSearchParameters params = extractAnimalSearchParamsFromCommand(searchCommand);

	List<Animal> animalLists = farmService.searchWithParams(params, pageNo);
	model.put("animals", animalLists);
	model.put(WebConstants.MODEL_ATTRIBUTE_SYSTEM_MESSAGE, String
		.format("search completed with: %s result(s)", String
			.valueOf(animalLists.size())));

	WebUtils.prepareNavigation("Animal", farmService.numberOfAnimalWithSearchParams(params),
		animalLists.size(), pageNo, buildNavigationUrl(params), model);

	prepareAnimalSearchFormLookUpLists(model);
	prepareAnimalSearchCommand(model, new AnimalSearchParameters());

	return new ModelAndView("reportView", model);
    }

    @Secured(PermissionConstants.PERM_VIEW_REPORT)
    @RequestMapping(method = RequestMethod.POST, params = { "action=search", "btnFilter=Export" })
    public void animalExportHandler(@ModelAttribute("animalsearch") GenericCommand command,
	    HttpServletResponse response) {
	AnimalSearchParameters params = extractAnimalSearchParamsFromCommand(command);
	InputStream stream = farmService.exportToExcel(params);
	try {
	    response.setContentType("application/vnd.ms-excel");
	    response.setHeader("Content-Disposition", "attachment; filename=AnimalReport.xls");
	    IOUtils.copy(stream, response.getOutputStream());
	} catch (IOException e) {
	}
    }

    /**
     * @param params
     * @return
     */
    private String buildNavigationUrl(AnimalSearchParameters params) {
	StringBuffer buffer = new StringBuffer();
	buffer.append("farm?action=search");

	if (params.getType() != null) {
	    buffer.append("&").append(ANIMAL_SEARCH_MODEL_PARAM_TYPE).append("=")
		    .append(params.getType().getName());
	}

	if (params.getHealthStatus() != null) {
	    buffer.append("&").append(ANIMAL_SEARCH_MODEL_PARAM_HEALTH_STATUS).append("=")
		    .append(params.getHealthStatus().getId());
	}

	if (params.getColor() != null) {
	    buffer.append("&").append(ANIMAL_SEARCH_MODEL_PARAM_COLOR).append("=")
		    .append(params.getColor().getId());
	}

	if (params.getKraal() != null) {
	    buffer.append("&").append(ANIMAL_SEARCH_MODEL_PARAM_KRAAL).append("=")
		    .append(params.getKraal().getId());
	}

	if (params.getBreed() != null) {
	    buffer.append("&").append(ANIMAL_SEARCH_MODEL_PARAM_BREED).append("=")
		    .append(params.getBreed().getId());
	}

	if (params.getDateOfBirth() != null) {
	    buffer.append("&").append(ANIMAL_SEARCH_MODEL_PARAM_DATEOFBIRTH).append("=").append(
		    params.getBirthYear());
	}

	if (params.getStatus() != null) {
	    buffer.append("&").append(ANIMAL_SEARCH_MODEL_PARAM_STATUS).append("=").append(
		    params.getStatus().getId());
	}

	if (params.getWeight() > 0) {
	    buffer.append("&").append(ANIMAL_SEARCH_MODEL_PARAM_Weight).append("=").append(
		    params.getWeight());
	}

	return buffer.toString();
    }

    /**
     * @param searchCommand
     * @return
     */
    private AnimalSearchParameters extractAnimalSearchParamsFromCommand(GenericCommand searchCommand) {
	AnimalSearchParameters params = new AnimalSearchParameters();

	if (StringUtils.isNotBlank(searchCommand
		.getValue(ANIMAL_SEARCH_MODEL_PARAM_TYPE))) {
	    params.setType(conceptService.getConceptById(searchCommand
			    .getValue(FarmController.ANIMAL_SEARCH_MODEL_PARAM_TYPE)));
	}

	if (StringUtils.isNotBlank(searchCommand
		.getValue(ANIMAL_SEARCH_MODEL_PARAM_HEALTH_STATUS))) {
	    params.setHealthStatus(conceptService.getConceptById(searchCommand
			    .getValue(FarmController.ANIMAL_SEARCH_MODEL_PARAM_HEALTH_STATUS)));
	}

	if (StringUtils.isNotBlank(searchCommand
		.getValue(ANIMAL_SEARCH_MODEL_PARAM_COLOR))) {
	    params.setColor(conceptService.getConceptById(searchCommand
			    .getValue(FarmController.ANIMAL_SEARCH_MODEL_PARAM_COLOR)));
	}

	if (StringUtils.isNotBlank(searchCommand
		.getValue(ANIMAL_SEARCH_MODEL_PARAM_KRAAL))) {
	    params.setKraal(farmService.getKraalById(searchCommand
			    .getValue(FarmController.ANIMAL_SEARCH_MODEL_PARAM_KRAAL)));
	}

	if (StringUtils.isNotBlank(searchCommand
		.getValue(ANIMAL_SEARCH_MODEL_PARAM_BREED))) {
	    params.setBreed(conceptService.getConceptById(searchCommand
			    .getValue(FarmController.ANIMAL_SEARCH_MODEL_PARAM_BREED)));
	}

	if (StringUtils.isNotBlank(searchCommand
		.getValue(ANIMAL_SEARCH_MODEL_PARAM_DATEOFBIRTH))) {

	    datePropertyEditor.setAsText(searchCommand
		    .getValue(ANIMAL_SEARCH_MODEL_PARAM_DATEOFBIRTH));
	    params.setDateOfBirth((Date) datePropertyEditor.getValue());
	}

	if (StringUtils.isNotBlank(searchCommand
		.getValue(ANIMAL_SEARCH_MODEL_PARAM_STATUS))) {
	    params.setStatus(conceptService.getConceptById(searchCommand
			    .getValue(FarmController.ANIMAL_SEARCH_MODEL_PARAM_STATUS)));
	}

	if (StringUtils.isNotBlank(searchCommand
		.getValue(ANIMAL_SEARCH_MODEL_PARAM_Weight))) {
	    params.setWeight(Integer.parseInt(searchCommand
			    .getValue(FarmController.ANIMAL_SEARCH_MODEL_PARAM_Weight)));
	}

	return params;
    }
}